# -*- encoding: utf-8 -*-

# Copyright 2010 István Szentandrási
# <etude-music-player@googlegroups.com>

# This file is part of Etude.
#
# Etude is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as 
# published by the Free Software Foundation, either version 3 
# of the License, or (at your option) any later version.
#
# Etude is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Etude. If not, see <http://www.gnu.org/licenses/>.

import gobject
import os
import ConfigParser

from etude import main
from common import *

class Equalizer(gobject.GObject):

    """
    wrapper for the equalizer plugin
    """

    freqs = {
            '10': ('31', '62', '125', '250', '500', '1k', '2k', '4k', '8k', '16k'),
            '15': ('25', '40', '63', '100', '160', '250', '400', '630', '1k', '1.6k', 
                '2.5k', '4k', '6.3k', '10k', '16k'),  
            '25': ('25', '31.5', '40', '50', '80', '100', '125', '160', '250', '315', 
                '400', '500', '800', '1k', '1.25k', '1.6k', '2.5k', '3.15k', '4k', 
                '5k', '8k', '10k', '12.5k', '16k', '20k'), 
            '31': ('20', '25', '31.5', '40', '50', '63', '80', '100', '125', '160', 
                '200', '250', '315', '400', '500', '630', '800', '1k', '1.25k', 
                '1.6k', '2k', '2.5k', '3.15k', '4k', '5k', '6.3k', '8k', '10k', 
                '12.5k', '16k', '20k'),
            'legacy': ('60', '170', '310', '600', '1k', '3k', '6k', '12k', '14k', '16k')
            }


    def __init__(self, client):
        self.__gobject_init__()
        self.client = client
        self.bands = 15
        self.extra_filtering = 0
        self.gain = [ 0 for i in xrange(31) ]
        self.legacy = [ 0 for i in xrange(10) ]
        self.preamp = 0.0
        self.use_legacy = 0
        self.client.connect("e_configval_changed", self.config_changed)
        self.load_config()
        self.enabled = 0

    def load_config(self):
        """
        load equalizer related configs
        """
        self.__load_one('equalizer.use_legacy')
        self.__load_one('equalizer.bands')
        for i in xrange(31):
            self.__load_one('equalizer.gain%02d' % (i))
        for i in xrange(10):
            self.__load_one('equalizer.legacy%01d' % (i))
        self.__load_one('equalizer.extra_filtering')
        self.__load_one('equalizer.preamp')
        self.__load_one('equalizer.enabled')
        self.load_presets()

    def load_presets(self):
        """
        Get the presets from the configuration file
        """
        self.presets_conf = ConfigParser.ConfigParser()
        self.presets_conf.read([os.path.join(main.DATA_DIR, 'eq_presets.conf'),
                os.path.join(main.CONFIG_DIR, 'eq_presets.conf')])
        self.presets = [preset for preset in self.presets_conf.sections() if preset != 'Presets']
        self.presets.sort()

    def load_preset(self, preset):
        """
        Parse one preset from the configuration file
        """
        if preset not in self.presets:
            return False
        if self.use_legacy:
            list = self.freqs['legacy']
            for ind in xrange(10):
                try:
                    val = self.presets_conf.getfloat(preset, list[ind])
                except NoOptionError:
                    val = 0.0
                finally:
                    self.set_legacy(ind, val, fast=True)
        else:
            list = self.freqs[str(self.bands)]
            for ind in xrange(self.bands):
                try:
                    val = self.presets_conf.getfloat(preset, list[ind])
                except:
                    val = 0.0
                finally:
                    self.set_gain(ind, val, fast=True)
        return True

    def save_presets(self):
        try:
            cfgfile = open(os.path.join(main.CONFIG_DIR, 'eq_presets.conf'),'w')
        except IOError:
            pass
        else:
            self.presets_conf.write(cfgfile)
            cfgfile.close()

    def save_preset(self, preset_name):
        def get_freqs(freq_list):
            freq_vals = []
            for value in freq_list:
                if value[-1] == 'k':
                    freq = int(float(value[:-1])*1000)
                else:
                    freq = float(value)
                freq_vals.append(freq)
            return freq_vals
        if self.use_legacy:
            freq_iter = iter(get_freqs(self.freqs['legacy']))
            values_iter = iter(self.legacy)
        else:
            freq_iter = iter(get_freqs(self.freqs[str(self.bands)]))
            values_iter = iter(self.gain)

        names = [item for itlist in self.freqs.values() for item in itlist]
        unique_names = list(set(names))
        unique_freqs = get_freqs(unique_names)
        unique_names_iter = iter(unique_names)
        unique_map = {}
        for freq in unique_freqs:
            unique_map[freq] = unique_names_iter.next()
        unique_freqs.sort()

        if not self.presets_conf.has_section(preset_name):
            self.presets_conf.add_section(preset_name)

        f1 = freq_iter.next()
        v1 = values_iter.next()
        f2 = freq_iter.next()
        v2 = values_iter.next()
        end = False
        for freq in unique_freqs:
            if freq>f2 and not end:
                try:
                    new = freq_iter.next()
                except StopIteration:
                    end = True
                else:
                    f1 = f2
                    f2 = new
                    v1 = v2
                    v2 = values_iter.next()
            #using ratio instead of difference with frequencies, as it's logaritmic
            if freq<f1:
                new_value = (f1*1.0/freq)*(v1-v2)*(f1*1.0/f2) + v1
            elif end:
                new_value = (f2*1.0/freq)*(v2-v1)*(f1*1.0/f2) + v2
            elif freq == f1:
                new_value = v1
            elif freq == f2:
                new_value = v2
            else:
                new_value = (freq*1.0/f1)*(v2-v1)*(f1*1.0/f2) + v1
            nwstr = "%.1f" % max(-20.0, min(20.0, new_value))
            self.presets_conf.set(preset_name, unique_map[freq], nwstr)
        if preset_name not in self.presets:
            self.presets.append(preset_name)
        self.save_presets()

    def remove_preset(self, preset_name):
        if self.presets_conf.has_section(preset_name):
            self.presets_conf.remove_section(preset_name)
        try:
            self.presets.remove(preset_name)
        except IndexError:
            pass
        self.save_presets()
    
    @check_fast()
    def __load_one(self, key):
        self.client.config.get(unicode(key), lambda res: self.config_changed(self.client, key, res.value(), res))

    def config_changed(self, widget, key, value, res = None):
        """
        configuration value changed callback, If it's one of the
        config values for the equalizer update the local variables
        """
        if res != None:
            if res.is_error():
                return False
        if not key.startswith('equalizer'):
            return False
        data = -1
        key = key[len('equalizer.'):]
        if key == 'bands':
            self.bands = int(value)
        elif key == 'extra_filtering':
            self.extra_filtering = int(value)
        elif key.startswith('gain'):
            #print('changed', key, value)
            data = int(key[4:6])
            self.gain[data] = float(value)
            key = 'gain'
        elif key.startswith('legacy'):
            #print('changed', key, value)
            data = int(key[6:8])
            self.legacy[data] = float(value)
            key = 'legacy'
        elif key == 'preamp':
            self.preamp = float(value)
        elif key == 'use_legacy':
            self.use_legacy = int(value)
        elif key == 'enabled':
            self.enabled = int(value)
        else:
            return False
        self.emit("e_changed", key, data)
        return False
    
    def set_bands(self, band, fast = False, wait = False):
        """
        set the number of bands
        """
        if self.bands != band:
            self.client.config.set(u'equalizer.bands', unicode(band), fast = fast, wait = wait)

    def set_gain(self, index, value, fast = False, wait = False):
        #print('set gain', index, value)
        """
        set one of the frequencies
        """
        if self.gain[index] != value:
            self.client.config.set(u'equalizer.gain%02d' % index, u'%.1f' % value, fast = fast, wait = wait)

    def set_legacy(self, index, value, fast = False, wait = False):
        """
        set legacy values
        """
        if self.legacy[index] != value:
            self.client.config.set(u'equalizer.legacy%01d' % index, u'%.1f' % value, wait = wait, fast = fast)

    def set_use_legacy(self, use, fast = False, wait = False):
        """
        if the legacy equalizer should be used
        """
        v = 0
        if use:
            v = 1
        if self.use_legacy != v:
            self.client.config.set(u'equalizer.use_legacy', unicode(v), fast = fast, wait = wait)

    def set_preamp(self, value, fast = False, wait = False):
        """set the global preamp"""
        if self.preamp != value:
            self.client.config.set(u'equalizer.preamp', u'%.1f' % value, fast = fast, wait = wait)

    def set_extra_filtering(self, use, fast = False, wait = False):
        """set extra filtering - requires extra processor"""
        v = 0
        if use:
            v = 1
        if self.extra_filtering != v:
            self.client.config.set(u'equalizer.extra_filtering', unicode(v), fast = fast, wait = wait)

    def enable(self, enable, fast = False):
        """
        enable/disable equalizer
        """
        if enable == self.enabled:
            return
        if enable:
            self.client.config.set_effect(u'equalizer')
            self.client.config.set(u'equalizer.enabled', u'1', fast = fast)
        else:
            self.client.config.unset_effect(u'equalizer')
            self.client.config.set(u'equalizer.enabled', u'0', fast = fast)


gobject.type_register(Equalizer)

gobject.signal_new("e_changed", Equalizer, gobject.SIGNAL_RUN_LAST, 
        gobject.TYPE_BOOLEAN, (gobject.TYPE_STRING, gobject.TYPE_INT))
#the equalizer changed (equalizer_key, value)
#ex ('preamp', 4)
